home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / groff_src.lha / groff-1.10src / xditview / device.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-11  |  10.9 KB  |  588 lines

  1. /* device.c */
  2.  
  3. #include <stdio.h>
  4. #include <ctype.h>
  5.  
  6. #include <X11/Xos.h>
  7. #include <X11/Intrinsic.h>
  8.  
  9. #include "device.h"
  10.  
  11. #ifndef FONTPATH
  12. #define FONTPATH "/usr/local/lib/groff/font:/usr/local/lib/font:/usr/lib/font"
  13. #endif
  14.  
  15. #ifndef isascii
  16. #define isascii(c) (1)
  17. #endif
  18.  
  19. extern void exit();
  20. extern char *strtok(), *strchr();
  21. extern char *getenv();
  22.  
  23. /* Name of environment variable containing path to be used for
  24. searching for device and font description files. */
  25. #define FONTPATH_ENV_VAR  "GROFF_FONT_PATH"
  26.  
  27. #define WS " \t\r\n"
  28.  
  29. #ifndef INT_MIN
  30. /* Minimum and maximum values a `signed int' can hold.  */
  31. #define INT_MIN (-INT_MAX-1)
  32. #define INT_MAX 2147483647
  33. #endif
  34.  
  35. #define CHAR_TABLE_SIZE 307
  36.  
  37. struct _DeviceFont {
  38.     char *name;
  39.     int special;
  40.     DeviceFont *next;
  41.     Device *dev;
  42.     struct charinfo *char_table[CHAR_TABLE_SIZE];
  43.     struct charinfo *code_table[256];
  44. };
  45.  
  46. struct charinfo {
  47.     int width;
  48.     int code;
  49.     struct charinfo *next;
  50.     struct charinfo *code_next;
  51.     char name[1];
  52. };
  53.  
  54. static char *current_filename = 0;
  55. static int current_lineno = -1;
  56.  
  57. static void error();
  58. static FILE *open_device_file();
  59. static DeviceFont *load_font();
  60. static Device *new_device();
  61. static DeviceFont *new_font();
  62. static void delete_font();
  63. static unsigned hash_name();
  64. static struct charinfo *add_char();
  65. static int read_charset_section();
  66. static char *canonicalize_name();
  67.  
  68. static
  69. Device *new_device(name)
  70.     char *name;
  71. {
  72.     Device *dev;
  73.  
  74.     dev = XtNew(Device);
  75.     dev->sizescale = 1;
  76.     dev->res = 0;
  77.     dev->unitwidth = 0;
  78.     dev->fonts = 0;
  79.     dev->X11 = 0;
  80.     dev->paperlength = 0;
  81.     dev->paperwidth = 0;
  82.     dev->name = XtNewString(name);
  83.     return dev;
  84. }
  85.  
  86. void device_destroy(dev)
  87.     Device *dev;
  88. {
  89.     DeviceFont *f;
  90.     
  91.     if (!dev)
  92.     return;
  93.     f = dev->fonts;
  94.     while (f) {
  95.     DeviceFont *tem = f;
  96.     f = f->next;
  97.     delete_font(tem);
  98.     }
  99.     
  100.     XtFree(dev->name);
  101.     XtFree((char *)dev);
  102. }
  103.  
  104. Device *device_load(name)
  105.     char *name;
  106. {
  107.     Device *dev;
  108.     FILE *fp;
  109.     int err = 0;
  110.     char buf[256];
  111.  
  112.     fp = open_device_file(name, "DESC", ¤t_filename);
  113.     if (!fp)
  114.     return 0;
  115.     dev = new_device(name);
  116.     current_lineno = 0;
  117.     while (fgets(buf, sizeof(buf), fp)) {
  118.     char *p;
  119.     current_lineno++;
  120.     p = strtok(buf, WS);
  121.     if (p) {
  122.         int *np = 0;
  123.         char *q;
  124.  
  125.         if (strcmp(p, "charset") == 0)
  126.         break;
  127.         if (strcmp(p, "X11") == 0)
  128.         dev->X11 = 1;
  129.         else if (strcmp(p, "sizescale") == 0)
  130.         np = &dev->sizescale;
  131.          else if (strcmp(p, "res") == 0)
  132.         np = &dev->res;
  133.          else if (strcmp(p, "unitwidth") == 0)
  134.         np = &dev->unitwidth;
  135.          else if (strcmp(p, "paperwidth") == 0)
  136.         np = &dev->paperwidth;
  137.          else if (strcmp(p, "paperlength") == 0)
  138.         np = &dev->paperlength;
  139.         
  140.         if (np) {
  141.         q = strtok((char *)0, WS);
  142.         if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
  143.             error("bad argument");
  144.             err = 1;
  145.             break;
  146.         }
  147.         }    
  148.     }
  149.     }
  150.     fclose(fp);
  151.     current_lineno = -1;
  152.     if (!err) {
  153.     if (dev->res == 0) {
  154.         error("missing res line");
  155.         err = 1;
  156.     }
  157.     else if (dev->unitwidth == 0) {
  158.         error("missing unitwidth line");
  159.         err = 1;
  160.     }
  161.     }
  162.     if (dev->paperlength == 0)
  163.     dev->paperlength = dev->res*11;
  164.     if (dev->paperwidth == 0)
  165.     dev->paperwidth = dev->res*8 + dev->res/2;
  166.     if (err) {
  167.     device_destroy(dev);
  168.     dev = 0;
  169.     }
  170.     XtFree(current_filename);
  171.     current_filename = 0;
  172.     return dev;
  173. }
  174.  
  175.  
  176. DeviceFont *device_find_font(dev, name)
  177.     Device *dev;
  178.     char *name;
  179. {
  180.     DeviceFont *f;
  181.  
  182.     if (!dev)
  183.     return 0;
  184.     for (f = dev->fonts; f; f = f->next)
  185.     if (strcmp(f->name, name) == 0)
  186.         return f;
  187.     return load_font(dev, name);
  188. }
  189.  
  190. static
  191. DeviceFont *load_font(dev, name)
  192.     Device *dev;
  193.     char *name;
  194. {
  195.     FILE *fp;
  196.     char buf[256];
  197.     DeviceFont *f;
  198.     int special = 0;
  199.  
  200.     fp = open_device_file(dev->name, name, ¤t_filename);
  201.     if (!fp)
  202.     return 0;
  203.     current_lineno = 0;
  204.     for (;;) {
  205.     char *p;
  206.  
  207.     if (!fgets(buf, sizeof(buf), fp)) {
  208.         error("no charset line");
  209.         return 0;
  210.     }
  211.     current_lineno++;
  212.     p = strtok(buf, WS);
  213.     /* charset must be on a line by itself */
  214.     if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
  215.         break;
  216.     if (p && strcmp(p, "special") == 0)
  217.         special = 1;
  218.     }
  219.     f = new_font(name, dev);
  220.     f->special = special;
  221.     if (!read_charset_section(f, fp)) {
  222.     delete_font(f);
  223.     f = 0;
  224.     }
  225.     else {
  226.     f->next = dev->fonts;
  227.     dev->fonts = f;
  228.     }
  229.     fclose(fp);
  230.     XtFree(current_filename);
  231.     current_filename = 0;
  232.     return f;
  233. }
  234.  
  235. static
  236. DeviceFont *new_font(name, dev)
  237.     char *name;
  238.     Device *dev;
  239. {
  240.     int i;
  241.     DeviceFont *f;
  242.  
  243.     f = XtNew(DeviceFont);
  244.     f->name = XtNewString(name);
  245.     f->dev = dev;
  246.     f->special = 0;
  247.     f->next = 0;
  248.     for (i = 0; i < CHAR_TABLE_SIZE; i++)
  249.     f->char_table[i] = 0;
  250.     for (i = 0; i < 256; i++)
  251.     f->code_table[i] = 0;
  252.     return f;
  253. }
  254.  
  255. static
  256. void delete_font(f)
  257.     DeviceFont *f;
  258. {
  259.     int i;
  260.  
  261.     if (!f)
  262.     return;
  263.     XtFree(f->name);
  264.     for (i = 0; i < CHAR_TABLE_SIZE; i++) {
  265.     struct charinfo *ptr = f->char_table[i];
  266.     while (ptr) {
  267.         struct charinfo *tem = ptr;
  268.         ptr = ptr->next;
  269.         XtFree((char *)tem);
  270.     }
  271.     }
  272.     XtFree((char *)f);
  273. }
  274.  
  275.  
  276. static
  277. unsigned hash_name(name)
  278.     char *name;
  279. {
  280.     unsigned n = 0;
  281.     /* XXX do better than this */
  282.     while (*name)
  283.     n = (n << 1) ^ *name++;
  284.  
  285.     return n;
  286. }
  287.  
  288. static
  289. int scale_round(n, x, y)
  290.     int n, x, y;
  291. {
  292.   int y2;
  293.  
  294.   if (x == 0)
  295.     return 0;
  296.   y2 = y/2;
  297.   if (n >= 0) {
  298.     if (n <= (INT_MAX - y2)/x)
  299.       return (n*x + y2)/y;
  300.   }
  301.   else if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
  302.       return (n*x - y2)/y;
  303.   return (int)(n*(double)x/(double)y + .5);
  304. }
  305.  
  306. static
  307. char *canonicalize_name(s)
  308.     char *s;
  309. {
  310.     static char ch[2];
  311.     if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
  312.     char *p;
  313.     int n;
  314.  
  315.     for (p = s + 4; *p; p++)
  316.         if (!isascii(*p) || !isdigit((unsigned char)*p))
  317.         return s;
  318.     n = atoi(s + 4);
  319.     if (n >= 0 && n <= 0xff) {
  320.         ch[0] = (char)n;
  321.         return ch;
  322.     }
  323.     }
  324.     return s;
  325. }
  326.  
  327. /* Return 1 if the character is present in the font; widthp gets the
  328. width if non-null. */
  329.  
  330. int device_char_width(f, ps, name, widthp)
  331.     DeviceFont *f;
  332.     int ps;
  333.     char *name;
  334.     int *widthp;
  335. {
  336.     struct charinfo *p;
  337.  
  338.     name = canonicalize_name(name);
  339.     for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
  340.     if (!p)
  341.         return 0;
  342.     if (strcmp(p->name, name) == 0)
  343.         break;
  344.     }
  345.     *widthp = scale_round(p->width, ps, f->dev->unitwidth);
  346.     return 1;
  347. }
  348.  
  349. int device_code_width(f, ps, code, widthp)
  350.     DeviceFont *f;
  351.     int ps;
  352.     int code;
  353.     int *widthp;
  354. {
  355.     struct charinfo *p;
  356.  
  357.     for (p = f->code_table[code & 0xff];; p = p->code_next) {
  358.     if (!p)
  359.         return 0;
  360.     if (p->code == code)
  361.         break;
  362.     }
  363.     *widthp = scale_round(p->width, ps, f->dev->unitwidth);
  364.     return 1;
  365. }
  366.  
  367. char *device_name_for_code(f, code)
  368.     DeviceFont *f;
  369.     int code;
  370. {
  371.     static struct charinfo *state = 0;
  372.     if (f)
  373.     state = f->code_table[code & 0xff];
  374.     for (; state; state = state->code_next)
  375.     if (state->code == code && state->name[0] != '\0') {
  376.         char *name = state->name;
  377.         state = state->code_next;
  378.         return name;
  379.     }
  380.     return 0;
  381. }
  382.  
  383. int device_font_special(f)
  384.     DeviceFont *f;
  385. {
  386.     return f->special;
  387. }
  388.     
  389. static
  390. struct charinfo *add_char(f, name, width, code)
  391.     DeviceFont *f;
  392.     char *name;
  393.     int width, code;
  394. {
  395.     struct charinfo **pp;
  396.     struct charinfo *ci;
  397.     
  398.     name = canonicalize_name(name);
  399.     if (strcmp(name, "---") == 0)
  400.     name = "";
  401.  
  402.     ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
  403.                      + strlen(name) + 1);
  404.     
  405.     strcpy(ci->name, name);
  406.     ci->width = width;
  407.     ci->code = code;
  408.     
  409.     if (*name != '\0') {
  410.     pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
  411.     ci->next = *pp;
  412.     *pp = ci;
  413.     }
  414.     pp = &f->code_table[code & 0xff];
  415.     ci->code_next = *pp;
  416.     *pp = ci;
  417.     return ci;
  418. }
  419.  
  420. /* Return non-zero for success. */
  421.  
  422. static
  423. int read_charset_section(f, fp)
  424.     DeviceFont *f;
  425.     FILE *fp;
  426. {
  427.     struct charinfo *last_charinfo = 0;
  428.     char buf[256];
  429.  
  430.     while (fgets(buf, sizeof(buf), fp)) {
  431.     char *name;
  432.     int width;
  433.     int code;
  434.     char *p;
  435.  
  436.     current_lineno++;
  437.     name = strtok(buf, WS);
  438.     if (!name)
  439.         continue;        /* ignore blank lines */
  440.     p = strtok((char *)0, WS);
  441.     if (!p)            /* end of charset section */
  442.         break;
  443.     if (strcmp(p, "\"") == 0) {
  444.         if (!last_charinfo) {
  445.         error("first line of charset section cannot use `\"'");
  446.         return 0;
  447.         }
  448.         else
  449.         (void)add_char(f, name,
  450.                    last_charinfo->width, last_charinfo->code);
  451.     }
  452.     else {
  453.         char *q;
  454.         if (sscanf(p, "%d", &width) != 1) {
  455.         error("bad width field");
  456.         return 0;
  457.         }
  458.         p = strtok((char *)0, WS);
  459.         if (!p) {
  460.         error("missing type field");
  461.         return 0;
  462.         }
  463.         p = strtok((char *)0, WS);
  464.         if (!p) {
  465.         error("missing code field");
  466.         return 0;
  467.         }
  468.         code = (int)strtol(p, &q, 0);
  469.         if (q == p) {
  470.         error("bad code field");
  471.         return 0;
  472.         }
  473.         last_charinfo = add_char(f, name, width, code);
  474.     }
  475.     }
  476.     return 1;
  477. }
  478.  
  479. static
  480. FILE *find_file(file, path, result)
  481.     char *file, *path, **result;
  482. {
  483.   char *buf = NULL;
  484.   int bufsiz = 0;
  485.   int flen;
  486.   FILE *fp;
  487.   
  488.   *result = NULL;
  489.   
  490.   if (file == NULL)
  491.     return NULL;
  492.   if (*file == '\0')
  493.     return NULL;
  494.   
  495.   if (*file == '/') {
  496.     fp = fopen(file, "r");
  497.     if (fp)
  498.       *result = XtNewString(file);
  499.     return fp;
  500.   }
  501.   
  502.   flen = strlen(file);
  503.   
  504.   if (!path)
  505.     return NULL;
  506.   
  507.   while (*path) {
  508.     int len;
  509.     char *start, *end;
  510.     
  511.     start = path;
  512.     end = strchr(path, ':');
  513.     if (end)
  514.       path = end + 1;
  515.     else
  516.       path = end = strchr(path, '\0');
  517.     if (start >= end)
  518.       continue;
  519.     if (end[-1] == '/')
  520.       --end;
  521.     len = (end - start) + 1 + flen + 1;
  522.     if (len > bufsiz) {
  523.       if (buf)
  524.     buf = XtRealloc(buf, len);
  525.       else
  526.     buf = XtMalloc(len);
  527.       bufsiz = len;
  528.     }
  529.     memcpy(buf, start, end - start);
  530.     buf[end - start] = '/';
  531.     strcpy(buf + (end - start) + 1, file);
  532.     fp = fopen(buf, "r");
  533.     if (fp) {
  534.       *result = buf;
  535.       return fp;
  536.     }
  537.   }
  538.   XtFree(buf);
  539.   return NULL;
  540. }
  541.  
  542. static
  543. FILE *open_device_file(device_name, file_name, result)
  544.      char *device_name, *file_name, **result;
  545. {
  546.   char *buf, *path;
  547.   FILE *fp;
  548.  
  549.   buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
  550.   sprintf(buf, "dev%s/%s", device_name, file_name);
  551.   path = getenv(FONTPATH_ENV_VAR);
  552.   if (!path)
  553.     path = FONTPATH;
  554.   fp = find_file(buf, path, result);
  555.   if (!fp) {
  556.       fprintf(stderr, "can't find device file `%s'\n", file_name);
  557.       fflush(stderr);
  558.   }
  559.   XtFree(buf);
  560.   return fp;
  561. }
  562.  
  563. static
  564. void error(s)
  565.     char *s;
  566. {
  567.     if (current_filename) {
  568.     fprintf(stderr, "%s:", current_filename);
  569.     if (current_lineno > 0)
  570.         fprintf(stderr, "%d:", current_lineno);
  571.     putc(' ', stderr);
  572.     }
  573.     fputs(s, stderr);
  574.     putc('\n', stderr);
  575.     fflush(stderr);
  576. }
  577.  
  578. /*
  579. Local Variables:
  580. c-indent-level: 4
  581. c-continued-statement-offset: 4
  582. c-brace-offset: -4
  583. c-argdecl-indent: 4
  584. c-label-offset: -4
  585. c-tab-always-indent: nil
  586. End:
  587. */
  588.